package com.lovenote.common.controller;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.base.common.pagination.Page;
import com.base.common.util.FileUploadUtil;
import com.base.common.util.ImageScaleUtil;
import com.base.common.util.Utils;
import com.lovenote.common.dto.PasswordDto;
import com.lovenote.common.dto.ProfileDto;
import com.lovenote.common.global.GlobalDefine;
import com.lovenote.common.pojo.Attachment;
import com.lovenote.common.pojo.Note;
import com.lovenote.common.pojo.NoteCatalog;
import com.lovenote.common.pojo.User;
import com.lovenote.common.pojo.UserProfile;
import com.lovenote.common.service.IAttachmentService;
import com.lovenote.common.service.INoteCatalogService;
import com.lovenote.common.service.INoteService;
import com.lovenote.common.service.IUserProfileService;
import com.lovenote.common.service.IUserService;

/**
 * User controller
 * @author xingkong1221
 *
 */
@Controller
public class UserController {
	
	private static final Logger logger = Logger.getLogger(UserController.class);
	
	@Autowired
	@Qualifier("userService")
	private IUserService userService;
	
	@Autowired
	@Qualifier("userProfileService")
	private IUserProfileService userProfileService;
	
	@Autowired
	@Qualifier("attachmentService")
	private IAttachmentService attachmentService;
	
	@Autowired
	@Qualifier("noteCatalogService")
	private INoteCatalogService noteCatalogService;
	
	@Autowired
	@Qualifier("noteService")
	private INoteService noteService;
	
	/**
	 * Return login page
	 * @return
	 */
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String login() {
		return "user/login";
	}
	
	/**
	 * Handle the login request
	 * @param model
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public Map<String, Object> loginAction(Model model, HttpServletRequest request, HttpServletResponse response) {
		Map<String, Object> result = new HashMap<String, Object>();
		// Get username & password, and set default value null
		String username = ServletRequestUtils.getStringParameter(request, "username", null);
		String password = ServletRequestUtils.getStringParameter(request, "password", null);
		
		if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
			// username and password are not empty
			User user = this.userService.authIdentity(username, password);
			if (user != null) {
				// Login success
				String avatar = new StringBuilder(request.getContextPath()).append("/images/noavatar.gif").toString();
				if (user.getAvatar() > 0) {
					Attachment attachment = this.attachmentService.get(user.getAvatar());
					avatar = new StringBuilder(request.getContextPath()).append("/").append(attachment.getAttachment()).append(attachment.getFilename()).toString();
				}
				// create session
				createSession(request, user, avatar);
				result.put("result", true);
				result.put("url", request.getContextPath() + "/home/" + user.getId());
			} else {
				// Login failure
				result.put("result", false);
			}
		}
		return result;
	}
	
	/**
	 * Return homepage
	 * @param model
	 * @param id
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/home/{id}", method = RequestMethod.GET)
	public String home(Model model, @PathVariable("id") long id, HttpServletRequest request) {
		User user = (User) request.getSession().getAttribute("user");
		
		if (user != null && user.getId() == id) {
			// Get total number of notes
			long total = this.noteService.countAll();
			// Get page number
			int pageNumber = ServletRequestUtils.getIntParameter(request, "p", 1);
			// Create a new page object
			Page page = new Page(total, pageNumber);
			page.setSort("dateline");		// set <dateline> as sort field
			page.setDir("desc");			// set <descend> as sort direction
			page.initialize();
			
			List<Note> noteList = this.noteService.list(page, "userId", user.getId());
			if (noteList.size() > 0) {
				List<NoteCatalog> noteCatalogList = this.noteCatalogService.loadByProperty("userId", user.getId());
				if (noteCatalogList.size() > 0) {
					Map<Integer, String> noteCatalogMap = new HashMap<Integer, String>();
					for (NoteCatalog noteCatalog : noteCatalogList) {
						noteCatalogMap.put(noteCatalog.getId(), noteCatalog.getName());
					}
					model.addAttribute("noteCatalogMap", noteCatalogMap);
				}
				model.addAttribute("noteList", noteList);
				model.addAttribute("page", page);
				model.addAttribute("hasNoteList", true);
			}
			// View the own homepage
			model.addAttribute("user", user);
			model.addAttribute("isOwn", true);
			
			List<NoteCatalog> noteCatalogs = this.noteCatalogService.getNoteCatalogList(user.getId());
			if (noteCatalogs.size() > 0) {
				model.addAttribute("noteCatalogs", noteCatalogs);
				model.addAttribute("isNoteCatalogs", true);
			}
		}
		model.addAttribute("id", id);
		return "user/home";
	}
	
	/**
	 * Handle logout request
	 * @param request
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "/logout", method = RequestMethod.GET)
	public Map<String, Object> logoutAction(HttpServletRequest request) {
		Map<String, Object> result = new HashMap<String, Object>();
		String status = (String) request.getSession().getAttribute("status");
		if (!StringUtils.isEmpty(status) && status.equals(GlobalDefine.USER_STATUS.IN)) {
			request.getSession().invalidate(); 		// Invalidate current session
			result.put("result", true);
		} else {
			result.put("result", false);
		}
		result.put("url", request.getContextPath() + "/login");
		return result; 
	}
	
	/**
	 * Return user information setting page
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/setting", method = RequestMethod.GET)
	public String setting(Model model, HttpServletRequest request) {
		User user = (User) request.getSession().getAttribute("user");
		UserProfile userProfile = (UserProfile) this.userProfileService.get(user.getId());
		model.addAttribute("user", user);
		model.addAttribute("profile", userProfile);
		return "user/setting";
	}
	
	/**
	 * Handle modify profile request
	 * @param model
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "/setting/profile", method = RequestMethod.POST)
	public Map<String, Object> profile(Model model, @ModelAttribute("profileDto") @Valid ProfileDto profileDto, BindingResult result, HttpServletRequest request) {
		Map<String, Object> message = new HashMap<String, Object>();
		
		// Detect errors
		if (result.hasErrors()) {
			List<FieldError> errors = result.getFieldErrors();		// Get errors
			List<String> errorList = new ArrayList<String>();	
			for (FieldError error : errors) {
				errorList.add(error.getDefaultMessage());			// put the default error message into errorList
			}
			message.put("result", false);
			message.put("error", errorList);
		} else {
			// update email and signature
			User user = (User) request.getSession().getAttribute("user");
			user.setEmail(profileDto.getEmail());
			user.setSignature(profileDto.getSignature());
			this.userService.update(user);
			// update realname, gender, mobile, age
			UserProfile userProfile = new UserProfile();
			userProfile.setRealname(profileDto.getRealname());
			userProfile.setGender(profileDto.getGender());
			if (profileDto.getAge() != null)
				userProfile.setAge(profileDto.getAge());
			userProfile.setMobile(profileDto.getMobile());
			userProfile.setId(user.getId());
			this.userProfileService.update(userProfile);
			message.put("result", true);
		}
		return message;
	}
	
	/**
	 * Handle modify password request
	 * @param model
	 * @param passwordDto
	 * @param result
	 * @param request
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "/setting/password", method = RequestMethod.POST)
	public Map<String, Object> password(Model model, @ModelAttribute("passwordDto") @Valid PasswordDto passwordDto, BindingResult result, HttpServletRequest request) {
		Map<String, Object> message = new HashMap<String, Object>();
		
		// Compare newPassword to confirmPassword
		if (!passwordDto.getNewPassword().equals(passwordDto.getConfirmPassword())) {		
			result.rejectValue("confirmPassword", null, "两次密码不一致");
		}
		
		// Verify the current password
		User user = (User) request.getSession().getAttribute("user");
		if (!user.getPassword().equals(Utils.MD5(user.getUsername() + passwordDto.getCurrentPassword()).toLowerCase())) {
			result.rejectValue("currentPassword", null, "当前密码不正确");
		}
		
		// Detect errors
		if (result.hasErrors()) {
			List<FieldError> errors = result.getFieldErrors();		// Get errors
			List<String> errorList = new ArrayList<String>();
			for (FieldError error : errors) {
				errorList.add(error.getDefaultMessage());			// Put error message into errorList
			}
			message.put("result", false);
			message.put("error", errorList);
		} else {
			user.setPassword(Utils.MD5(user.getUsername() + passwordDto.getNewPassword()).toLowerCase());
			this.userService.update(user);
			message.put("result", true);
		}
		
		return message;
	}
	
	/**
	 * Handle modify avatar request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/setting/avatar", method = RequestMethod.POST)
	public String avatar(Model model, @RequestParam("file") MultipartFile multipartFile, HttpServletRequest request) throws IllegalStateException, IOException {
		String script = "";
		if (!multipartFile.isEmpty()) {
			String type = FileUploadUtil.isImage(multipartFile.getInputStream());
			if (type != null) {
				// Get root directory
				String root = request.getSession().getServletContext().getRealPath("/");
				
				// Build upload directory
				StringBuilder dir = new StringBuilder("upload/avatar/");
				dir.append(FileUploadUtil.generateSavePath());
				
				StringBuilder path = new StringBuilder(root).append(dir);
				
				// Check if directory is exists
				FileUploadUtil.checkOrCreateFilePath(path.toString());

				// Generate a new name
				StringBuilder name = new StringBuilder(FileUploadUtil.generateNewFileName());
				name.append(".");
				name.append(type);
				
				path.append(name);
				File file = new File(path.toString());
				
				// Transfer file
				multipartFile.transferTo(file);
				ImageScaleUtil.scaleImageByLong(file, 80, type);
				
				StringBuilder httpPath = new StringBuilder(request.getContextPath()).append("/").append(dir).append(name);
				
				User user = (User) request.getSession().getAttribute("user");
				if (user.getAvatar() <= 0) {
					// Have no avatar
					Attachment attachment = new Attachment();
					attachment.setUserId(user.getId());
					attachment.setImage(true);
					attachment.setDateline(new Date());
					attachment.setFilesize(0); 			// 暂时不处理
					attachment.setFilename(name.toString());
					attachment.setAttachment(dir.toString());
					this.attachmentService.save(attachment);
					user.setAvatar(attachment.getId());
					this.userService.update(user);
				} else {
					// Have avatar
					Attachment attachment = this.attachmentService.get(user.getAvatar());
					attachment.setAttachment(dir.toString());
					attachment.setDateline(new Date());
					attachment.setFilename(name.toString());
					this.attachmentService.update(attachment);
				}
				createSession(request, user, httpPath.toString());
				script = "parent.alert('头像上传成功');parent.refresh_avatar('" + httpPath.toString() + "')";
			} else {
				script = "parent.alert('上传的不是图片');";
			}
		} else {
			script = "parent.alert('没有选择图片');";
			
		}
		model.addAttribute("script", script);
		return "user/avatar";
	}
	
	/**
	 * Create session on server side
	 * @param request
	 * @param user
	 */
	private void createSession(HttpServletRequest request, User user, String avatar) {
		HttpSession session = request.getSession(true);		// If there is no current session, returns a new session
		session.setMaxInactiveInterval(10 * 60); 	// 10min
		session.setAttribute("status", GlobalDefine.USER_STATUS.IN);
		session.setAttribute("user", user);
		session.setAttribute("avatar", avatar);
	}
}
